﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DataInput;
using Slaks.Graphs.GraphBuilder;
using Slaks.Graphs.Algorithms;
using Slaks.Graphs.GraphBuilder.Schenker;
using Slaks.Graphs.GraphBuilder.Slaks;
using Slaks.Graphs.ShenkerGraph;
using Slaks.Graphs.GraphBuilder.Schenker;
using Slaks.Graphs.GraphBuilder.Slaks;
using Slaks.Graphs;
using Slaks.Graphs.Analysis;


namespace UI
{
    public partial class ExperimentDesign : Form
    {
        private List<Group> _groups = new List<Group>();
        
        String IterationsParam = "Iterations";
        String SkipParsingParam = "SkipParsing";
        String RemoveStopWordsParam = "RemoveStopWords";

        TaskType taskType = TaskType.Categorization;
        string builderTypeValue = "StandardSimpleRepresentationSlaks";
        String algorithmName = "";
        ExperimentItem itm;

        public ExperimentItem Itm
        {
            get { return itm; }
            set { itm = value; }
        }        

        public void initializeFields()
        {
            Dictionary<string, object> task = new Dictionary<string, object>();
            List<Field> innerFields = new List<Field> ();            
            task.Add("Categorization", TaskType.Categorization);
            task.Add("Clustering", TaskType.Clustering);
            innerFields.Add(new ListField("TaskType", "Task Type:", TaskType.Categorization, task, false));
            innerFields.Add(new TextField(ExperimentItem.CategoryFileNameParam, "Categories File:", false));
            innerFields.Add(new NumericField(ExperimentItem.IterationsParam, "Iterations:", "10", false));
            Group TaskFields = new Group("Task properties:", innerFields, true);
            innerFields = new List<Field>();   
            innerFields.Add(new TextField(ExperimentItem.SourceFolderParam,"Input directory:", false));
            innerFields.Add(new TextField(ExperimentItem.TargetFolderParam, "Output directory:", false));
            innerFields.Add(new BooleanField(ExperimentItem.SkipParsingParam, "Skip parsing:", "0",false));
            innerFields.Add(new TextField(ExperimentItem.RemoveStopWordsParam, "Stop words file:", "",true));
            innerFields.Add(new TextField(ExperimentItem.ResultsFileNameParam, "Output file name:",false));
            Group DocumentFields = new Group("Document settings:", innerFields, true);
            String[] algorithms = CategorizationFactory.Instance.AvailableAlgoirthmsNames.ToArray<String> ();
            algorithmName = algorithms [ 0 ];
            Dictionary<String, Object> allAlgorithms = new Dictionary<string, object>();
            for (int i = 0; i < algorithms.Length; i++)
                allAlgorithms.Add(algorithms[i], algorithms[i]);
            innerFields = new List<Field> ();
            innerFields.Add(new ListField("Algorithm", "Algorithm Name:", algorithmName, allAlgorithms, false));
            Group TaskAlgorithm = new Group("Task Algorithm:", innerFields, false);
            _groups.Add(TaskFields);
            _groups.Add(DocumentFields);
            _groups.Add(TaskAlgorithm);
            if (taskType == TaskType.Categorization)
            {
                innerFields = CategorizationFactory.Instance.GetInstance(algorithmName).GetDynamicFields(GraphBuilderFactory.Instance.GetInstance(builderTypeValue));
            }
            else
            {
                innerFields = ClusteringFactory.Instance.GetInstance(algorithmName).GetDynamicFields(GraphBuilderFactory.Instance.GetInstance(builderTypeValue));
            }
            Group TaskAlgorithmParameters = new Group("Task Algorithm Parameters:", innerFields, false);            
            innerFields = new List<Field>();
            Dictionary<string, object> builderTypes = (from algorithm in GraphBuilderFactory.Instance.AvailableAlgoirthmsNames
                    select algorithm as object).ToDictionary(a => a.ToString());
            
            //GraphBuilderBase.getAllBuilderTypes();
            innerFields.Add(new ListField(GraphBuilderBase.BuilderTypeParam, "Builder Type:", builderTypeValue, builderTypes, false)); 
            Group GraphFields = new Group("Graph Builder:", innerFields, true);            
            _groups.Add(GraphFields);
            innerFields = GraphBuilderFactory.Instance.GetInstance(builderTypeValue).GetDynamicFields();
            Group GraphParameters = new Group("Graph Parameters:", innerFields, true);
            if (innerFields.Count > 0)
                _groups.Add(GraphParameters);
            _groups.Add(TaskAlgorithmParameters);
            innerFields = new List<Field>();
            String[] allMeasures = CategorizationMeasureFactory.Instance.AvailableAlgoirthmsNames.ToArray<String>();
            Dictionary<string, object> allMeasuresD = (from algorithm in allMeasures
                                                       select algorithm as object).ToDictionary(a => a.ToString());
            innerFields.Add(new MultiListField(Measures.measuresParam, "Evaluation Measures:", new List<Object> (), allMeasuresD, false)); 
            Group MeasureFields = new Group("measures:", innerFields, true); 
            _groups.Add(MeasureFields);
        }


        Field findField(List<Field> fields, String fieldName )
        {
            for (int i = 0; i < fields.Count; i++)
                if (fields[i].FieldName == fieldName)
                    return fields[i];
            return null;
        }

        Field findField(Group grp, String fieldName)
        {
            return findField(grp.Fields, fieldName);
        }

        Field findField(List<Group> grps, String fieldName)
        {
            for (int i = 0; i < grps.Count; i++)
            {
                Field fld = findField(grps[i], fieldName);
                if (fld != null)
                    return fld;
            }
            return null;
        }

        Group findGroup(List<Group> grps, String groupName)
        {
            for (int i = 0; i < grps.Count; i++)
            {
                if (grps[i].GroupName == groupName)
                    return grps[i];
            }
            return null;
        }


        void replaceGroup(List<Group> groups, Group group, int position)
        {
            int i = 0;
            for (i = 0; (i < groups.Count && groups[i].GroupName != group.GroupName); i++) ;
            if (i < groups.Count)
            {
                groups.Remove(groups[i]);
            }
            if (position > groups.Count)
                position = groups.Count;       
            groups.Insert(position, group);
        }

        void removeGroup(List<Group> groups, Group group)
        {
            int i = 0;
            for (i = 0; (i < groups.Count && groups[i].GroupName != group.GroupName); i++) ;
            if (i < groups.Count)
            {
                groups.Remove(groups[i]);
            }            
        }

        public ExperimentDesign()
        {            
            InitializeComponent();
            initializeFields();
            AddGraphRepresentation();
            inputControl1.GroupWidth = 317;
            inputControl1.setFields(_groups);
            inputControl1.fieldChanged += new EventHandler(inputControl1_fieldChanged);
        }

        void inputControl1_fieldChanged(object sender, EventArgs e)
        {
            bool relevantValueChanged = false;
            Field field = (Field)sender;
            if (field.FieldName == GraphBuilderBase.BuilderTypeParam)
            {
                builderTypeValue = field.Value as string;
                List<Field> innerFields;
                innerFields = GraphBuilderFactory.Instance.GetInstance(builderTypeValue).GetDynamicFields();
                Group GraphParameters = new Group("Graph Parameters:", innerFields, true);
                if (innerFields.Count > 0)
                    replaceGroup(_groups, GraphParameters, 4);
                else
                    removeGroup(_groups, GraphParameters);
                if (taskType == TaskType.Categorization)
                    innerFields = CategorizationFactory.Instance.GetInstance(algorithmName).GetDynamicFields(GraphBuilderFactory.Instance.GetInstance(builderTypeValue));
                else
                    innerFields = ClusteringFactory.Instance.GetInstance(algorithmName).GetDynamicFields(GraphBuilderFactory.Instance.GetInstance(builderTypeValue));
                Group TaskAlgorithmParameters = new Group("Task Algorithm Parameters:", innerFields, false);
                if (innerFields.Count > 0)
                    replaceGroup(_groups, TaskAlgorithmParameters, 5);
                else
                    removeGroup(_groups, TaskAlgorithmParameters);
                relevantValueChanged = true;
            }
            if (field.FieldName == "TaskType")
            {
                taskType = (TaskType)field.Value;
                List<Field> innerFields = new List<Field>();
                String[] allMeasures;
                if ( taskType == TaskType.Categorization )
                    allMeasures = CategorizationMeasureFactory.Instance.AvailableAlgoirthmsNames.ToArray<String>();
                else
                    allMeasures = ClusteringMeasureFactory.Instance.AvailableAlgoirthmsNames.ToArray<String>();
                Dictionary<string, object> allMeasuresD = (from algorithm in allMeasures
                                                           select algorithm as object).ToDictionary(a => a.ToString());
                innerFields.Add(new MultiListField(Measures.measuresParam, "Evaluation Measures:", new List<Object> (), allMeasuresD, false));
                Group MeasureFields = new Group("measures:", innerFields, true);
                _groups.Add(MeasureFields);
                if (allMeasures.Length > 0)
                    replaceGroup(_groups, MeasureFields, 6);
                else
                    removeGroup(_groups, MeasureFields);
                relevantValueChanged = true;
            }
            if (field.FieldName == "Algorithm")
            {
                relevantValueChanged = true;
                algorithmName = field.Value.ToString();
            }
            if (field.FieldName == "Algorithm" || field.FieldName == "TaskType")
            {
                String[] algorithms = null;
                List<Field> innerFields;
                if (taskType == TaskType.Categorization)
                {
                    if (field.FieldName == "TaskType")
                    {
                        algorithms = CategorizationFactory.Instance.AvailableAlgoirthmsNames.ToArray();
                        algorithmName = algorithms[0];
                    }
                    innerFields = CategorizationFactory.Instance.GetInstance(algorithmName).GetDynamicFields(GraphBuilderFactory.Instance.GetInstance(builderTypeValue));
                }
                else
                {
                    if (field.FieldName == "TaskType")
                    {
                        algorithms = ClusteringFactory.Instance.AvailableAlgoirthmsNames.ToArray();
                        algorithmName = algorithms[0];
                    }
                    innerFields = ClusteringFactory.Instance.GetInstance(algorithmName).GetDynamicFields(GraphBuilderFactory.Instance.GetInstance(builderTypeValue));
                }
                if (algorithms != null)
                {
                    algorithmName = algorithms[0];
                    Dictionary<String, Object> allAlgorithms = new Dictionary<string, object>();
                    for (int i = 0; i < algorithms.Length; i++)
                        allAlgorithms.Add(algorithms[i], algorithms[i]);

                    List<Field> AlgFields = new List<Field>();
                    AlgFields.Add(new ListField("Algorithm", "Algorithm Name:", algorithmName, allAlgorithms, false));
                    Group TaskAlgorithm = new Group("Task Algorithm:", AlgFields, false);
                    if (allAlgorithms.Count > 0)
                        replaceGroup(_groups, TaskAlgorithm, 1);
                    else
                        removeGroup(_groups, TaskAlgorithm);
                }                
                
                Group TaskAlgorithmParameters = new Group("Task Algorithm Parameters:", innerFields, false);
                if (innerFields.Count > 0)
                    replaceGroup(_groups, TaskAlgorithmParameters, 5);
                else
                    removeGroup(_groups, TaskAlgorithmParameters);
                relevantValueChanged = true;
            }
            if ( relevantValueChanged )
                inputControl1.setFields(_groups);
        }

        private static void AddGraphRepresentation()
        {
//            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.StandardRepresentationSchenker, new StandardRepresentationSchenker());
//            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.SimpleRepresentationSchenker, new SimpleRepresentationSchenker());
//            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.NDistanceRepresentationSchenker, new NDistanceRepresentationSchenker());
//            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.NSimpleDistanceRepresentationSchenker, new NSimpleDistanceRepresentationSchenker());
//            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.RawFrequencyRepresentationSchenker, new RawFrequencyRepresentationSchenker());
//            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.NormalizedFrequencyRepresentationSchenker, new NormalizedFrequencyRepresentationSchenker());

//            //slaks representation
//            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.StandardRepresentationSlaks, new StandardRepresentationSlaks());
//            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.SimpleRepresentationSlaks, new SimpleRepresentationSlaks());
//            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.NDistanceRepresentationSlaks, new NDistanceRepresentationSlaks());
//            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.NSimpleDistanceRepresentationSlaks, new NSimpleDistanceRepresentationSlaks());
//            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.RawFrequencyRepresentationSlaks, new RawFrequencyRepresentationSlaks());
//            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.NormalizedFrequencyRepresentationSlaks, new NormalizedFrequencyRepresentationSlaks());

//            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.StandardSimpleRepresentationSlaks, new StandardSimpleRepresentationSlaks());

//            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.StandardBiderectionalRepresentationSlaks, new StandardBiderectionalRepresentationSlaks());
//            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.NDistanceBiderectionalRepresentationSlaks, new NDistanceBiderectionalRepresentationSlaks());

////            GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.ExtractorBuilderNodesOnly, new ExtractorBuilderNodesOnly());
        }

        public List<Field> allFields
        {
            get
            {
                List<Field> fields = new List<Field>();
                for (int i = 0; i < _groups.Count; i++)
                    for (int j = 0; j < _groups[i].Fields.Count; j++)
                        fields.Add(_groups[i].Fields[j]);                    
                for (int i = 0; i < _groups.Count; i++)
                    for (int j = 0; j < _groups[i].Fields.Count; j++)
                        fields.Add(_groups[i].Fields[j]);                
                return fields;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            String missingField = null;
            missingField = inputControl1.isComplete();
            if ( missingField == null )
            {
                this.DialogResult = DialogResult.OK;
                if (taskType == TaskType.Categorization)
                    itm = new CategorizationExperiment(allFields, CategorizationFactory.Instance.GetInstance(algorithmName), algorithmName);
                else
                    itm = new ClusteringExperiment(allFields, ClusteringFactory.Instance.GetInstance(algorithmName), algorithmName);
                Close();
            }
            else
            {
                MessageBox.Show("The required fields are not complete !\n Please fill in the field " + missingField );
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
            Close();
        }
    }
}
